import { uuid } from '../uuid';
import getScrollBarSize from './getScrollBarSize';

export interface scrollLockOptions {
  container: HTMLElement;
}

const scrollingEffectClassName = 'ant-scrolling-effect';
const scrollingEffectClassNameReg = new RegExp(
  `${scrollingEffectClassName}`,
  'g',
);

export default class ScrollLocker {
  private currContainerKey: string = '';
  private container: HTMLElement = document.body;
  private options: scrollLockOptions = { container: document.body };
  private static instance: ScrollLocker;
  private locks: { containerKey: string; container: HTMLElement }[] = [];

  private setData = (options: scrollLockOptions) => {
    this.options = options;
    this.container = options.container;
    this.currContainerKey = uuid();
  };

  //单例模式： 向外暴露静态方法getInstance
  public static getInstance(options: scrollLockOptions) {
    if (!ScrollLocker.instance) {
      ScrollLocker.instance = new ScrollLocker();
    }
    ScrollLocker.instance.setData(options);
    return ScrollLocker.instance;
  }

  lock = () => {
    // If lockTarget exist return
    if (
      this.locks.some(
        ({ containerKey }) => containerKey === this.currContainerKey,
      )
    ) {
      return;
    }

    // If same container effect, return ,多个dialog共用一个container
    if (this.locks.some(({ container }) => container === this.container)) {
      this.locks = [
        ...this.locks,
        { containerKey: this.currContainerKey, container: this.container },
      ]; //合并
      return;
    }

    let scrollBarSize = 0;
    const container = this.options?.container || document.body;
    // 且遮罩position:'fixed' 是针对html的, window.innerWidth - document.documentElement.clientWidth> 0 说明有滚动条，且滚动条在html上
    if (
      (container === document.body &&
        window.innerWidth - document.documentElement.clientWidth > 0) ||
      container.scrollHeight > container.clientHeight
    ) {
      if (getComputedStyle(container).overflow !== 'hidden') {
        scrollBarSize = getScrollBarSize();
      }
    }

    const containerClassName = container.className;
    if (
      this.locks.filter(({ container }) => container === this.container)
        .length === 0
    ) {
      if (scrollBarSize) {
        this.container.style.width = `calc(100% - ${scrollBarSize}px)`;
        this.container.style.overflow = 'hidden';
      }
      if (!scrollingEffectClassNameReg.test(containerClassName)) {
        const addClassName = `${containerClassName} ${scrollingEffectClassName}`;
        container.className = addClassName.trim();
      }
    }
  };

  unLock = () => {
    const findLock = this.locks.find(
      ({ containerKey }) => containerKey === this.currContainerKey,
    );
    this.locks = this.locks.filter(
      ({ containerKey }) => containerKey !== this.currContainerKey,
    );
    if (
      !findLock ||
      this.locks.some(
        // 多个dialog共用一个container
        ({ container }) => container === findLock.container,
      )
    ) {
      return;
    }
    // Remove Effect
    const container = this.container || document.body;
    const containerClassName = container.className;
    if (!scrollingEffectClassNameReg.test(containerClassName)) return;
    container.removeAttribute('style');
    container.className = container.className
      .replace(scrollingEffectClassNameReg, '')
      .trim();
  };
}
